<template>
  <a-modal
    v-model="isModalVisible"
    :width="currentWidth"
    :height="modalHeight"
    :dialog-style="{ top: '64px' }"
    :destroy-on-close="true"
    :z-index="1000"
    :mask-closable="false"
    :keyboard="true"
    @cancel="handleCancel"
  >
    <template slot="title">
      <div class="left-btn">
        <span class="function-run-text">按示例新增列</span>
        <span class="divider"></span>
        <a-tooltip
          v-for="(tip, index) in functionList"
          :key="index"
          placement="top"
        >
          <template slot="title">
            <span>{{ tip.tooltip }}</span>
          </template>
          <div
            class="btn function-btn-spacing"
            @click="clickFunction(tip.click)"
          >
            <a-icon-font :type="tip.icon" />
          </div>
        </a-tooltip>
      </div>
    </template>
    <template slot="footer">
      <span class="table-info">{{ totalRows }}行 {{ uniqueRows }}个唯一值</span>
      <a-button key="back" @click="handleCancel">
        取消
      </a-button>
      <a-button key="submit" type="primary" @click="handleOk">
        确认
      </a-button>
    </template>
    <div class="table-box">
      <ux-grid
        :data="tableData"
        :height="currentHeight"
        :row-height="rowHeight"
        :edit-config="{ trigger: 'click', mode: 'cell' }"
        :highlight-current-row="false"
        :stripe="true"
        use-virtual
        @table-body-scroll="handleScroll"
        @header-click="_headerClick"
      >
        <ux-table-column
          :title="'序号'"
          type="index"
          width="70"
        ></ux-table-column>
        <ux-table-column title="源数据列">
          <ux-table-column :title="columnName" :field="columnName" width="220">
            <template #header="{ column }">
              <a-icon-font :type="columnTypeIcon[columnData.desc]" />
              <span class="column-name">{{ column.title }}</span>
            </template>
          </ux-table-column>
        </ux-table-column>
        <ux-table-column title="新数据列">
          <ux-table-column
            :edit-render="{ autofocus: '.new-column-input' }"
            :field="newColumnName"
            :title="newColumnName"
            width="220"
          >
            <template #header>
              <a-icon-font :type="columnTypeIcon[newColumnNameDesc]" />
              <span v-if="!isEditingColumnName" class="column-name">{{
                newColumnName
              }}</span>
              <input
                v-else
                ref="nameInput"
                v-model="newColumnName"
                class="column-name"
                @blur="onColumnNameChange"
                @keyup.enter="onColumnNameChange"
              />
            </template>
            <span
              slot-scope="scope"
              :class="{
                'auto-filled': !ifFilledBefore(scope.row),
              }"
            >
              {{ scope.row[newColumnName] }}
            </span>
            <template #edit="{ row }">
              <input
                v-model="row[newColumnName]"
                class="new-column-input"
                @blur="onBlur(row)"
                @keyup.enter="$event.target.blur"
              />
            </template>
          </ux-table-column>
        </ux-table-column>
      </ux-grid>
    </div>
  </a-modal>
</template>

<script lang="ts">
import { Prop, Component, Vue, Emit, Watch } from 'vue-property-decorator'
import DataStore from '@/store/modules/dataview'
// @ts-ignore
import { UxGrid, UxTableColumn } from 'umy-table'
import { apiGetTableData } from '@/api/data-clean'
import { throttle } from 'lodash'
import Big from 'big.js'

interface KeyValue {
  [key: string]: any
}

@Component({
  components: {
    UxGrid,
    UxTableColumn,
  },
})
export default class CreateColumnView extends Vue {
  @Prop() columnData!: any // 弹窗显示
  @Prop({ type: Number, default: () => 0 }) totalRows!: number // 该列数据的总数
  @Prop({ type: Number, default: () => 0 }) uniqueRows!: number // 该列数据的唯一值数

  private isEditingColumnName: boolean = false
  private isModalVisible: boolean = true
  private times = 1
  private rowHeight = 14
  private totalPages: number = 0
  private isLoading = false
  public functionList: any[] = [
    // TODO undo redo func
    // {tooltip: 'undo', click: 'undo', icon: 'iconhoutui1'},
    // {tooltip: 'redo', click: 'redo', icon: 'iconqianjin'},
    { tooltip: 'delete', click: 'bulkDelete', icon: 'iconicon-beifen5' },
  ]
  private columnTypeIcon = {
    int: 'iconshujuleixing-shuzi',
    decimal: 'iconshujuleixing-shuzi',
    string: 'iconshujuleixing-zifu',
    date: 'iconshujuleixing-riqi',
    text: 'iconshujuleixing-zifu',
    varchar: 'iconshujuleixing-zifu',
  }
  private dataType = new Map([
    ['int', -5],
    ['decimal', 2],
    ['string', -1],
    ['default', -5],
  ])
  private newColumnName: string = ''
  private newColumnNameDesc: string = 'string'
  private newColumn: Array<object> = [{}]
  private filterParam = {}
  private specificParams: KeyValue = {}
  private outputType: string = ''

  private changeMapping = new Map() //  记录实施的 源-目标 值的转换
  private rules = new Map() //  记录所匹配到的规则 {origin => rules}
  private operationUndoList: Array<any> = [] //  撤回操作列表
  private operationRedoList: Array<any> = [] //  重做操作列表
  private nonRulesMatched: Boolean = true //  是否没有规则匹配上

  mounted() {
    this.totalPages = DataStore.totalPages
    this.newColumnName = this.CreateNewColumnName()
  }

  public get currentWidth(): number {
    return document.body.clientWidth
  }

  public get currentHeight(): number {
    return document.body.clientHeight - 64 - 110
  }

  public get modalHeight(): number {
    return document.body.clientHeight - 64
  }

  public get selectNode() {
    return DataStore.selectNode
  }

  public get tableData() {
    return DataStore.tableData
  }

  private get currentHistory() {
    return DataStore.currentHistory
  }

  private CreateNewColumnName() {
    //  防止重名；
    let index = 1
    let i = 0
    const { length } = this.tableColumns
    while (i < length) {
      if (this.tableColumns[i].name === `${this.columnName}_${index}`) {
        index += 1
        i = 0
      } else {
        i += 1
      }
    }

    return `${this.columnName}_${index}`
  }

  public get tableColumns() {
    return DataStore.tableColumns
  }

  private fieldList: any = {}

  public get columnName() {
    return this.columnData?.name
  }

  // 多个功能 统一点击入口
  public clickFunction(functionName: string) {
    //  TODO undo/redo/delete
    if (functionName === 'bulkDelete') {
      this.bulkDelete()
    }
  }

  public bulkDelete() {
    this.clearDataAfterCancel()
  }

  /**
   * 重命名新列名
   */
  private onColumnNameChange() {
    // @ts-ignore
    for (let i = 0, { length } = this.tableColumns; i < length; i += 1) {
      if (this.tableColumns[i].name === this.newColumnName) {
        this.$message.error('列名已存在，请重新输入')
        return
      }
    }
    this.isEditingColumnName = false
  }

  @Watch('isEditingColumnName')
  public onIsEditingColumnName(newValue: boolean) {
    if (newValue) {
      this.$nextTick(() => {
        const name = this.$refs.nameInput as HTMLElement
        // @ts-ignore
        name.focus()
      })
    }
  }

  public ifFilledBefore(row: any) {
    const key = row[this.columnName]
    if (this.changeMapping.has(key)) {
      return true
    }
    return false
  }

  private onBlur(row: any) {
    console.log(row[this.columnName], row[this.newColumnName])
    const value = row[this.newColumnName]
    if (!value) {
      return
    }
    //  获取源和目的数据类型
    const destinationType = this.ifOriginDataTypeIsStr()
      ? 'string'
      : this.defineDataType(value)
    this.outputType = destinationType
    // const originType = this.defineDataType(row[this.newColumnName])
    const originType = this.columnData.desc
    const origin = row[this.columnName] //  源数据

    //  源-目标不同类型值需要做的规则匹配检测
    const actions = new Map([
      ['int-int', this.integerRepeatAndStringFill],
      ['int-decimal', this.integerStringFill],
      ['int-string', this.integerStringFill],
      ['decimal-int', this.decimalShiftAndRetain],
      ['decimal-decimal', this.decimalShiftAndRetain],
      ['decimal-string', this.decimalRepeat],
      ['date-string', this.dateCaseCheck],
      ['date-int', this.dateCaseCheck],
      ['default', this.stringCaseCheck], //  text-string, varchar-string and date-string, multiple rules
    ])
    const action: any =
      actions.get(`${originType}-${destinationType}`) || actions.get('default')
    action.call(this, origin, value)

    if (this.nonRulesMatched) {
      this.handleNoRulesMatched(origin, value)
      this.nonRulesMatched = true
    }

    this.handleMappingChange(origin, value)
  }

  /**
   * 处理新值旧值映射的关系
   * @param value       源数据
   * @param destination 改动后数据
   */
  private handleMappingChange(origin: any, destination: any) {
    const destinationType = this.defineDataType(destination)
    if (this.changeMapping.has(origin)) {
      this.changeMapping.delete(origin)
    }
    this.changeMapping.set(origin, destination) //  变换后的值 - 变换前的值
    console.log('~~~~新值旧值映射：', this.changeMapping)
    this.newColumnNameDesc = this.ifOriginDataTypeIsStr()
      ? 'string'
      : destinationType

    const type =
      this.operationUndoList[this.operationUndoList.length - 1]?.flag ?? 'none'
    if (type === 'STRING_FILLING') {
      this.newColumnNameDesc = 'string'
    }
  }

  private ifOriginDataTypeIsStr() {
    const filter = ['string', 'text', 'varchar']
    return filter.includes(this.columnData.desc)
  }

  /**
   * 检测数据的类型： 整数，小数，字符串
   * @param value 源数据 [原本为字符串，所以要经过转换判断]
   * @returns string 数据类型
   */
  private defineDataType(value: string) {
    if (!Number.isNaN(value)) {
      // 是否为数字
      if (/^[+-]?\d+$/.test(value)) {
        // 整数
        return 'int'
      }
      if (/^[+-]?\d+\.\d+$/.test(value)) {
        //  小数
        return this.columnData.desc === 'int' ? 'string' : 'decimal' //  源为整数，若目的为小数，则目标列类型应为字符串
      }
      return 'string' //  10. 的情况
    } //  字符串
    return 'string'
  }

  /**
   * 将某个规则映射到其余的数据
   * @param result 执行规则转换所需数据
   * @param func 执行规则的函数
   * @param flag 规则的名称
   * @param origin 源列数据
   * @param value 目标列数据
   * @param history 是否从undo, redo, scrollMap 里执行操作
   */
  private mappingDataByRules(
    result: any,
    func: any,
    flag: string,
    origin: any,
    value: any,
    history?: boolean
  ) {
    this.nonRulesMatched = false
    if (!history) {
      this.operationUndoList.push({
        result,
        func,
        flag,
        origin,
        value,
      })
    }

    //  同一个规则，允许一类参数；
    // eslint-disable-next-line no-restricted-syntax
    for (const [key, ruleValue] of this.rules) {
      if (ruleValue === flag) {
        this.rules.delete(key)
      }
    }

    if (this.rules.has(origin)) {
      this.rules.delete(origin)
    }
    this.rules.set(origin, flag) //  存放匹配到的规则情况
    console.log('~~~~~~~现存的规则', this.rules)

    //  只存在一种规则的情况
    if (this.rules.size <= 1) {
      this.tableData.forEach((v, i) => {
        if (!this.tableData[i][this.columnName]) {
          // 源为空的数据，依旧为空
          // this.tableData[i][this.newColumnName] = ''
          Vue.set(this.tableData[i], this.newColumnName, '')
        } else {
          Vue.set(
            this.tableData[i],
            this.newColumnName,
            func(v[this.columnName], result)
          ) //  剩余数据遵循该规则转换
        }
      })
    } else {
      //  存在多种规则的情况
      this.tableData.forEach((v, i) => {
        if (!this.tableData[i][this.columnName]) {
          // 源为空的数据，依旧为空
          Vue.set(this.tableData[i], this.newColumnName, '')
        } else if (
          this.changeMapping.get(this.tableData[i][this.columnName]) &&
          this.tableData[i][this.columnName] !== origin
        ) {
          //  检测该值是否存在转换并且不等于目前改变的值
          Vue.set(
            this.tableData[i],
            this.newColumnName,
            this.changeMapping.get(this.tableData[i][this.columnName])
          ) //  直接从转换表里取值赋值
        } else {
          Vue.set(this.tableData[i], this.newColumnName, value) // 默认赋值为最后一个改动的值
        }
      })
    }
    switch (flag) {
      case 'INT_REPEAT':
        this.specificParams = {
          transformType: 'INT_REPEAT', //  整数重复
          repeatNum: result, //  重复次数
        }
        break
      case 'STRING_FILLING':
        this.specificParams = {
          transformType: 'STRING_FILLING', //  字符串填充
          prefix: result[0], //  首部填充
          suffix: result[1], //  尾部填充
        }
        break
      case 'DECIMAL_POINT_MOVE':
        this.specificParams = {
          transformType: 'DECIMAL_POINT_MOVE',
          moveNum: result,
        }
        break
      case 'DECIMAL_RETAIN':
        this.specificParams = {
          transformType: result[0].toUpperCase(),
          retainNum: result[1],
        }
        break
      case 'STRING_REPEAT':
        this.specificParams = {
          transformType: 'STRING_REPEAT', //  字符串重复
          repeatNum: result, //  重复次数
        }
        break
      case 'WORD_REMOVE':
        this.specificParams = {
          transformType: 'WORD_REMOVE', //  单词去除
          starts: result[0] + 1, //  从第a 个单词开始
          removeNum: result[1], //  去除单词个数
        }
        break
      case 'WORD_RETAIN':
        this.specificParams = {
          transformType: 'WORD_RETAIN',
          starts: result[0] + 1,
          retainNum: result[1],
        }
        break
      case 'STRING_INSERT':
        this.specificParams = {
          transformType: 'STRING_INSERT',
          wordIndex: result[0] + 1,
          insertValue: result[1],
        }
        break
      case 'WORD_CASE':
        // result  是记录所有的字符串； 不变则为0， 首大1 首小2 全大3 全小4
        // eslint-disable-next-line no-case-declarations
        const data = []
        for (let i = 0, { length } = result; i < length; i += 1) {
          if (result[i] === 0) {
            // eslint-disable-next-line no-continue
            continue
          }
          data.push({
            wordIndex: i + 1,
            caseType: result[i],
          })
        }
        this.specificParams = {
          transformType: 'WORD_CASE',
          wordCase: data,
        }
        break
      case 'WORD_INITIAL':
        // result  是记录所有的字符串； 不变则为0， 小写2  大写3
        // eslint-disable-next-line no-case-declarations
        const dataWord = []
        for (let i = 0, { length } = result; i < length; i += 1) {
          if (result[i] === 0) {
            // eslint-disable-next-line no-continue
            continue
          }
          dataWord.push({
            wordIndex: i + 1,
            caseType: result[i],
          })
        }
        this.specificParams = {
          transformType: 'WORD_INITIAL',
          words: dataWord,
        }
        break
      case 'SPECIAL_CHARACTER_REPLACE':
        this.specificParams = {
          transformType: 'SPECIAL_CHARACTER_REPLACE',
          originValue: result[0],
          replaceValue: result[1],
        }
        break
      case 'CURSOR_REMOVE':
        this.specificParams = {
          transformType: 'CURSOR_REMOVE',
          cursorStart: result[0],
          cursorEnd: result[0] + result[1],
        }
        break
      case 'CURSOR_RETAIN':
        this.specificParams = {
          transformType: 'CURSOR_RETAIN',
          cursorStart: result[0],
          cursorEnd: result[0] + result[1],
        }
        break
      case 'DATE_FORMAT':
        this.specificParams = {
          transformType: 'DATE_FORMAT',
          params: result, //  应该格式已经一致
        }
        break
      case 'MATCH_SUBSTRING':
        this.specificParams = {
          transformType: 'STRING_MATCHING',
          substring: result,
        }
        break
      default:
        break
    }
  }

  /**
   * 检测是否满足 重复 || 字符串填充 规则
   * 针对 integer - integer
   */
  private integerRepeatAndStringFill(origin: string, value: string) {
    const times = this.isRepeated(origin, value) //  20 -> 2020
    if (times) {
      console.log('整数重复')
      this.mappingDataByRules(
        times,
        this.applyRepeated,
        'INT_REPEAT',
        origin,
        value
      )
    } else {
      // 2020 -> 2020998
      const result = this.isStrFilling(origin, value)
      if (result) {
        console.log('整数-字符串填充')
        this.mappingDataByRules(
          result,
          this.applyStrFilling,
          'STRING_FILLING',
          origin,
          value
        )
      }
    }
  }

  /**
   * 检测是否满足 字符串填充 规则
   * 针对 integer - 其他
   */
  private integerStringFill(origin: string, value: string) {
    const result = this.isStrFilling(origin, value) // 20 -> #20
    if (result) {
      console.log('整数-字符串填充')
      this.mappingDataByRules(
        result,
        this.applyStrFilling,
        'STRING_FILLING',
        origin,
        value
      )
    }
  }

  /**
   * 检测是否满足 小数点移位 规则
   * 针对 decimal - integer
   */
  private decimalPointShift(origin: string, value: string) {
    const shiftIndex = this.isdecimalShift(
      Number.parseFloat(origin),
      Number.parseFloat(value)
    ) //  0.2 -> 0.02
    if (shiftIndex) {
      console.log('小数-小数点移位')
      this.mappingDataByRules(
        shiftIndex,
        this.decimalShift,
        'DECIMAL_POINT_MOVE',
        origin,
        value
      )
    }
  }

  /**
   * 检测是否满足 小数点移位 || 保留小数 规则
   * 针对 decimal - decimal
   */
  private decimalShiftAndRetain(origin: string, value: string) {
    const shiftIndex = this.isdecimalShift(
      Number.parseFloat(origin),
      Number.parseFloat(value)
    ) //  0.2 -> 0.02
    if (shiftIndex) {
      console.log('小数-小数点移位')
      this.mappingDataByRules(
        shiftIndex,
        this.decimalShift,
        'DECIMAL_POINT_MOVE',
        origin,
        value
      )
    } else {
      const array: any = this.ifRetainDecimals(origin, value)
      if (array) {
        console.log('小数-保留小数')
        this.mappingDataByRules(
          array,
          this.retainDecimals,
          'DECIMAL_RETAIN',
          origin,
          value
        )
      }
    }
  }

  /**
   * 检测是否满足 重复 规则
   * 针对 decimal - string
   */
  private decimalRepeat(origin: string, value: string) {
    const times = this.isRepeated(origin, value) //  20 -> 2020
    if (times) {
      console.log('小数/字符串重复')
      this.mappingDataByRules(
        times,
        this.applyRepeated,
        'STRING_REPEAT',
        origin,
        value
      )
    }
  }

  //  handle non rule matched case
  private handleNoRulesMatched(origin: any, value: any) {
    console.log('没有匹配任何规则')
    this.rules.set(origin, 'noneRuleMatched')
    this.mappingDataForNoneRulesMatched(origin, value)
    this.operationUndoList.push({
      origin,
      value,
    })
  }

  /**
   * 检测是否满足 日期 转换的规则
   * 针对 date - string
   */
  private dateCaseCheck(origin: string, value: string) {
    if (this.ifDateFormatChange(origin, value)) {
      const arrayCase: any = this.ifDateFormatChange(origin, value)
      console.log('时间格式')
      this.mappingDataByRules(
        arrayCase,
        this.dateFormatChange,
        'DATE_FORMAT',
        origin,
        value
      )
    }
  }

  /**
   * 检测是否满足 字符串 规则
   * 针对 string - others
   */
  private stringCaseCheck(origin: string, value: string) {
    if (this.ifMatchSubstring(origin, value)) {
      console.log('子串匹配')
      const destination = this.ifMatchSubstring(origin, value)
      this.mappingDataByRules(
        destination,
        this.matchSubstring,
        'MATCH_SUBSTRING',
        origin,
        value
      )
    } else if (this.ifRemoveWords(origin, value)) {
      console.log('单词去除')
      const array: any = this.ifRemoveWords(origin, value)
      this.mappingDataByRules(
        array,
        this.removeStr,
        'WORD_REMOVE',
        origin,
        value
      )
    } else if (this.ifPreserveStr(origin, value)) {
      const arrayOne: any = this.ifPreserveStr(origin, value)
      console.log('单词保留')
      this.mappingDataByRules(
        arrayOne,
        this.preserveStr,
        'WORD_RETAIN',
        origin,
        value
      )
    } else if (this.isRepeated(origin, value)) {
      const times: any = this.isRepeated(origin, value)
      console.log('字符串重复')
      this.mappingDataByRules(
        times,
        this.applyRepeated,
        'STRING_REPEAT',
        origin,
        value
      )
    } else if (this.isStrFilling(origin, value)) {
      const result: any = this.isStrFilling(origin, value)
      this.mappingDataByRules(
        result,
        this.applyStrFilling,
        'STRING_FILLING',
        origin,
        value
      )
      console.log('整数-字符串填充')
    } else if (this.ifInsertStr(origin, value)) {
      const arrayInsert: any = this.ifInsertStr(origin, value)
      console.log('插入单词')
      this.mappingDataByRules(
        arrayInsert,
        this.insertStr,
        'STRING_INSERT',
        origin,
        value
      )
    } else if (this.ifSwitchCase(origin, value)) {
      const arrayCase: any = this.ifSwitchCase(origin, value)
      console.log('大小写切换')
      this.mappingDataByRules(
        arrayCase,
        this.switchCase,
        'WORD_CASE',
        origin,
        value
      )
    } else if (this.ifPreserveAbbr(origin, value)) {
      const arrayCase: any = this.ifPreserveAbbr(origin, value)
      console.log('单词缩写')
      this.mappingDataByRules(
        arrayCase,
        this.preserveAbbr,
        'WORD_INITIAL',
        origin,
        value
      )
    } else if (this.ifSpecialCharacterReplace(origin, value)) {
      const arrayCase: any = this.ifSpecialCharacterReplace(origin, value)
      console.log('特殊字符替换')
      this.mappingDataByRules(
        arrayCase,
        this.specialCharacterReplace,
        'SPECIAL_CHARACTER_REPLACE',
        origin,
        value
      )
    } else if (this.ifRemoveCharacter(origin, value)) {
      const arrayCase: any = this.ifRemoveCharacter(origin, value)
      console.log('下标去除')
      this.mappingDataByRules(
        arrayCase,
        this.removeCharacter,
        'CURSOR_REMOVE',
        origin,
        value
      )
    } else if (this.ifPreserveCha(origin, value)) {
      const arrayCase: any = this.ifPreserveCha(origin, value)
      console.log('下标保留')
      this.mappingDataByRules(
        arrayCase,
        this.preserveCha,
        'CURSOR_RETAIN',
        origin,
        value
      )
    }
  }

  private mappingDataForNoneRulesMatched(origin: string, value: string) {
    this.tableData.forEach((v, i) => {
      if (!this.tableData[i][this.columnName]) {
        Vue.set(this.tableData[i], this.newColumnName, '')
      } else if (
        this.changeMapping.get(this.tableData[i][this.columnName]) &&
        this.tableData[i][this.columnName] !== origin
      ) {
        Vue.set(
          this.tableData[i],
          this.newColumnName,
          this.changeMapping.get(this.tableData[i][this.columnName])
        )
      } else {
        Vue.set(this.tableData[i], this.newColumnName, value)
      }
    })
  }

  /**
   * 检测是否符合 日期-字符串 转换规则 2015-04-15 → 2015年4月
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns [object] 存放timeUnit & desc 的对象数组
   */
  private ifDateFormatChange(ori: string, destination: string) {
    // 目前只支持一种格式 yyyy-MM-dd HH:mm:ss
    //  匹配格式 yyyy-MM-dd HH:mm:ss
    const reg = /^(\d{4})-(\d{1,2})-(\d{1,2})\s(\d{1,2}):(\d{1,2}):(\d{1,2})$/
    //  匹配 例2020年11月11日11点12分30秒 [完整格式] 中间描述不一定为中文
    const extractReg = /^(\d{4})?(\D+)?(\d{1,2})?(\D+)?(\d{1,2})?(\D+)?(\d{1,2})?(\D+)?(\d{1,2})?(\D+)?(\d{1,2})?(\D+)?$/
    if (!reg.test(ori) || !extractReg.test(destination)) {
      return false
    }
    //  获取转换后的日期称谓
    const resultArray: any = extractReg.exec(destination)
    const parametersArray: any = []
    for (let i = 2, { length } = resultArray; i < length; i += 2) {
      if (!resultArray[i]) {
        // eslint-disable-next-line no-continue
        continue
      }
      switch (i) {
        case 2:
          parametersArray.push({
            timeUnit: 'YYYY',
            desc: resultArray[i],
          })
          break
        case 4:
          parametersArray.push({
            timeUnit: resultArray[i].startsWith('0') ? 'MM' : 'FMMM', //  FM 表示去除前导0
            desc: resultArray[i],
          })
          break
        case 6:
          parametersArray.push({
            timeUnit: resultArray[i].startsWith('0') ? 'DD' : 'FMDD',
            desc: resultArray[i],
          })
          break
        case 8:
          parametersArray.push({
            timeUnit: resultArray[i].startsWith('0') ? 'HH' : 'FMHH',
            desc: resultArray[i],
          })
          break
        case 10:
          parametersArray.push({
            timeUnit: resultArray[i].startsWith('0') ? 'MI' : 'FMMI',
            desc: resultArray[i],
          })
          break
        case 12:
          parametersArray.push({
            timeUnit: resultArray[i].startsWith('0') ? 'SS' : 'FMSS',
            desc: resultArray[i],
          })
          break
        default:
          break
      }
    }
    if (parametersArray.length === 0) {
      return false
    }
    return parametersArray // 返回转换所需数据
  }

  /**
   * 执行日期-字符串 规则转换 2015-04-15 → 2015年4月
   * @param ori 源列数据
   * @param array 转换所需数据
   */
  private dateFormatChange(ori: string, array: Array<any>) {
    //  匹配格式 yyyy-MM-dd HH:mm:ss
    const reg = /^(\d{4})-(\d{1,2})-(\d{1,2})\s(\d{1,2}):(\d{1,2}):(\d{1,2})$/
    if (!reg.test(ori)) {
      return ''
    }
    const resultArray: any = reg.exec(ori)
    let destination = ''
    for (let i = 0, { length } = array; i < length; i += 1) {
      switch (array[i].timeUnit) {
        case 'YYYY':
          destination += resultArray[1] + array[i].desc
          break
        case 'MM':
          destination += resultArray[2] + array[i].desc
          break
        case 'DD':
          destination += resultArray[3] + array[i].desc
          break
        case 'HH':
          destination += resultArray[4] + array[i].desc
          break
        case 'MI':
          destination += resultArray[5] + array[i].desc
          break
        case 'SS':
          destination += resultArray[6] + array[i].desc
          break
        case 'FMMM':
          destination += resultArray[2].replace(/\b(0+)/g, '') + array[i].desc //  做前导0 的去除
          break
        case 'FMDD':
          destination += resultArray[3].replace(/\b(0+)/g, '') + array[i].desc
          break
        case 'FMHH':
          destination += resultArray[4].replace(/\b(0+)/g, '') + array[i].desc
          break
        case 'FMMI':
          destination += resultArray[5].replace(/\b(0+)/g, '') + array[i].desc
          break
        case 'FMSS':
          destination += resultArray[6].replace(/\b(0+)/g, '') + array[i].desc
          break
        default:
          break
      }
    }
    return destination
  }

  /**
   * 检测是否符合 字符串-下标保留 转换规则 ##abc → abc；则a=2，b=3
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns [a, b] 从下标a开始，保留b个字符
   */
  private ifPreserveCha(ori: string, destination: string) {
    // 考虑保留中间的字符即可，首部末尾的情况会被字符去除匹配
    //  需要考虑 前面有字符重复的情况 比如 2018-10-11 -》 11
    const pos = ori.indexOf(destination)
    if (pos !== -1) {
      return [pos, destination.length]
    }
    return false
  }

  /**
   * 执行字符串-下标保留 转换规则 ##abc → abc
   * @param ori 源列数据
   * @param array [a, b] 从下标a开始，保留b个字符
   */
  private preserveCha(ori: string, array: Array<number>) {
    const oriArray = ori.split('')
    const result = oriArray.splice(array[0], array[array.length - 1])
    return result.join('')
  }

  /**
   * 检测是否符合 字符串-下标去除 转换规则 ##abc → abc；则a=0，b=2
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns [a, b] 从下标a开始，去除b个字符
   */
  private ifRemoveCharacter(ori: string, destination: string) {
    //  从第a个下标开始，删除b个字符   [左边边界，右边边界，中间]
    const oriLength = ori.length
    const outLength = destination.length
    const b = oriLength - outLength
    const array = []
    let j = 0
    for (let i = 0; i < oriLength; i += 1) {
      if (ori[i] === destination[j]) {
        j += 1
        // eslint-disable-next-line no-continue
        continue
      } else {
        array.push(i)
      }
    }
    if (
      array.length > 0 &&
      j === outLength &&
      array.length + outLength === oriLength
    ) {
      if (!this.isNumberContinuous(array)) {
        return false
      } //  保证只发生一处，即去除动作是连续的
      return [array[0], b]
    }
    return false
  }

  /**
   * 执行字符串-下标去除 转换规则 ##abc → abc
   * @param ori 源列数据
   * @param array [a, b] 从下标a开始，去除b个字符
   */
  private removeCharacter(ori: string, array: Array<number>) {
    // 需要考虑若范围超出如何处理
    const oriArray = ori.split('')
    oriArray.splice(array[0], array[array.length - 1])
    return oriArray.join('')
  }

  /**
   * 检测是否符合 特殊字符替换 特殊字符指的是非数字非字母的字符，转换的字符可以是任意字符（或字符串）（默认是全部替换）
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns [a, b] a为被替换的特殊字符 b为转换后的字符
   */
  private ifSpecialCharacterReplace(ori: string, destination: string) {
    //  若不存在特殊字符，直接返回
    if (!/[^\dA-Za-z]/.test(ori)) {
      return false
    }
    const oriLength = ori.length
    const destinationLength = destination.length
    let i = 0
    let j = 0
    let speChara = ''
    let newString = ''
    for (i = 0; i < oriLength; i += 1) {
      if (ori[i] !== destination[j]) {
        if (!/[^\dA-Za-z]/.test(ori[i])) {
          return false
        }
        speChara = ori[i]
        let temporaryIndex = j
        while (ori[i + 1] !== destination[temporaryIndex]) {
          newString += destination[temporaryIndex]
          temporaryIndex += 1
          if (temporaryIndex >= destinationLength) {
            break
          }
        }
        if (ori.replaceAll(speChara, newString) === destination) {
          return [speChara, newString]
        }
      }
      j += 1
      if (j >= destinationLength) {
        return false
      }
    }
    return false
  }

  /**
   * 实行特殊字符替换
   * @param ori 源列数据
   * @param array [a, b] a为被替换的特殊字符 b为转换后的字符
   */
  private specialCharacterReplace(ori: string, array: Array<string>) {
    const oriChara = array[0]
    const destinationChara = array[1]
    return ori.replaceAll(oriChara, destinationChara)
  }

  /**
   * 检测是否符合 缩写：只保留单词首字母 Jim Mitchum → JM
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns array 记录每个单词首字母的大小写情况
   */
  private ifPreserveAbbr(ori: string, destination: string) {
    // jim ted -> JT 默认dest至少有两位
    const oriArray = ori.split(' ')
    const array = []
    if (
      /^[^\dA-Za-z]*$/.test(destination) ||
      oriArray.length <= 1 ||
      /[\u4E00-\u9FA5]+/.test(destination)
    ) {
      return false
    }
    for (let i = 0, { length } = oriArray; i < length; i += 1) {
      if (destination[i] === oriArray[i][0]) {
        array.push(0) //  保持原样
        // eslint-disable-next-line no-continue
        continue
      } else if (destination[i] === oriArray[i][0].toLowerCase()) {
        array.push('LOWER') //  转换为小写
        // eslint-disable-next-line no-continue
        continue
      } else if (destination[i] === oriArray[i][0].toUpperCase()) {
        array.push('UPPER') //  转换为大写
        // eslint-disable-next-line no-continue
        continue
      } else {
        return false
      }
    }
    return array
  }

  /**
   * 执行缩写：只保留单词首字母 转换规则 Jim Mitchum → JM
   * @param ori 源列数据
   * @param array 转换所需数据
   */
  private preserveAbbr(ori: string, array: Array<any>) {
    let result = ''
    const oriArray = ori.split(' ')
    const { length } = oriArray
    for (let i = 0; i < length; i += 1) {
      switch (array[i]) {
        case 0: //  保持不变
          result += oriArray[i][0]
          break
        case 'LOWER': // 转小写
          result += oriArray[i][0].toLowerCase()
          break
        case 'UPPER': // 转大写
          result += oriArray[i][0].toUpperCase()
          break
        default:
          //  默认保持不变 当array.length<oriArray.length
          result += oriArray[i][0]
          break
      }
    }
    return result
  }

  /**
   * 检测是否符合 大小写切换  只考虑这四种情况 首大1 首小2 全大3 全小4
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns array 记录每个单词的大小写情况
   */
  private ifSwitchCase(ori: string, destination: string) {
    if (ori.toLowerCase() !== destination.toLowerCase()) {
      return false
    }
    const oriArray = ori.split(' ')
    const outArray = destination.split(' ')
    const array = []
    const { length } = outArray
    for (let i = 0; i < length; i += 1) {
      if (outArray[i] === oriArray[i]) {
        //  没有改变的情况
        array.push(0)
        // eslint-disable-next-line no-continue
        continue
      } else if (outArray[i] === oriArray[i].toUpperCase()) {
        //  全大写的情况
        array.push('UPPER')
        // eslint-disable-next-line no-continue
        continue
      } else if (outArray[i] === oriArray[i].toLowerCase()) {
        //  全小写的情况
        array.push('LOWER')
        // eslint-disable-next-line no-continue
        continue
      } else if (
        outArray[i][0] === oriArray[i][0].toUpperCase() &&
        outArray[i].slice(1) === oriArray[i].slice(1)
      ) {
        //  首字母大写的情况
        array.push('FIRST_UPPER')
        // eslint-disable-next-line no-continue
        continue
      } else if (
        outArray[i][0] === oriArray[i][0].toLowerCase() &&
        outArray[i].slice(1) === oriArray[i].slice(1)
      ) {
        //  首字母小写的情况
        array.push('FIRST_LOWER')
        // eslint-disable-next-line no-continue
        continue
      } else {
        return false
      }
    }
    return array
  }

  /**
   * 执行大小写切换 转换规则 考虑这四种情况 首大1 首小2 全大3 全小4
   * @param ori 源列数据
   * @param array 转换所需数据
   */
  private switchCase(ori: string, array: Array<any>) {
    const oriArray = ori.split(' ')
    const outArray: any = []
    const { length } = oriArray
    for (let i = 0; i < length; i += 1) {
      switch (array[i]) {
        case 'FIRST_UPPER': //  首大1
          outArray[i] = oriArray[i][0].toUpperCase() + oriArray[i].slice(1)
          break
        case 'FIRST_LOWER': // 首小2
          outArray[i] = oriArray[i][0].toLowerCase() + oriArray[i].slice(1)
          break
        case 'UPPER': // 全大3
          outArray[i] = oriArray[i].toUpperCase()
          break
        case 'LOWER': // 全小4
          outArray[i] = oriArray[i].toLowerCase()
          break
        default:
          //  考虑oriArray，array 长度不一致的情况  以及 没有变动的情况 case 0
          outArray[i] = oriArray[i]
      }
    }
    return outArray.join(' ')
  }

  /**
   * 检测是否符合 中间填充字符串（单词） one three -> one two three
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns [i, s] 在第i个单词位置处，填充字符串（单词）s
   */
  private ifInsertStr(ori: string, destination: string) {
    //  insert a word
    const oriArray = ori.split(' ')
    const outArray = destination.split(' ')
    const outlength = outArray.length
    if (outlength <= oriArray.length) {
      return false
    }
    let pos = -1
    let word
    for (let i = 0, j = 0; i < outlength; i += 1) {
      if (oriArray[j] === outArray[i]) {
        j += 1
        // eslint-disable-next-line no-continue
        continue
      } else if (pos === -1) {
        //  考虑连续； 因为是单词，所以中间只可能有一个值
        pos = i
        word = outArray[i]
      } else {
        return false
      }
    }
    return [pos, word]
  }

  /**
   * 执行中间填充字符串（单词） one three -> one two three
   * @param ori 源列数据
   * @param array 转换所需数据 [i, s] 在第i个单词位置处，填充字符串（单词）s
   */
  private insertStr(ori: string, array: Array<any>) {
    const pos = array[0]
    const string = array[1]
    const oriArray = ori.split(' ')
    oriArray.splice(pos, 0, string)
    return oriArray.join(' ')
  }

  /**
   * 检测是否符合 子串匹配 豚骨拉面 -> 拉面
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns destination 子串数据
   */
  private ifMatchSubstring(ori: string, destination: string) {
    if (ori.includes(destination)) {
      return destination
    }
    return false
  }

  /**
   * 执行子串匹配 豚骨拉面 -> 拉面
   * @param ori 源列数据
   * @param destination 包含的子串，如果有的话直接填充
   */
  private matchSubstring(ori: string, destination: string) {
    return ori.includes(destination) ? destination : ori
  }

  /**
   * 检测是否符合 单词保留 tony is good man -> good
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns [a, b] // 从第a个单词开始，保留b个单词
   */
  private ifPreserveStr(ori: string, destination: string) {
    if (ori.split(' ').length <= 1) {
      return false
    }
    const pos = ori.indexOf(destination)
    if (pos !== -1) {
      const oriArray = ori.split(' ')
      const outArray = destination.split(' ')
      let test = 0
      let firstWordPos = 0
      //  若outArray最后一个单词不是 完整的单词 比如   james harden -> james h

      // 确定dest 头单词在ori 中的位置
      // eslint-disable-next-line unicorn/no-for-loop
      for (let i = 0; i < oriArray.length; i += 1) {
        if (test < pos) {
          test += oriArray[i].length
          test += 1
        } else {
          firstWordPos = i
          break
        }
      }
      const { length } = outArray
      //  如果匹配上的最后一个单词是完整的，则满足单词保留规则
      if (oriArray[firstWordPos + length - 1] === outArray[length - 1]) {
        return [firstWordPos, destination.split(' ').length]
      }
    }
    return false
  }

  /**
   * 执行 单词保留 tony is good man -> good
   * @param ori 源列数据
   * @param array [a, b] // 从第a个单词开始，保留b个单词
   */
  private preserveStr(ori: string, array: Array<any>) {
    return ori
      .split(' ')
      .slice(array[0], array[0] + array[1])
      .join(' ')
  }

  /**
   * 检测是否符合 单词去除 tony is good man -> good man
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns [a, b] // 从第a个单词开始，去除b个单词
   */
  private ifRemoveWords(ori: string, destination: string) {
    const oriArray = ori.split(' ')
    const outArray = destination.split(' ')
    const oriLength = oriArray.length
    const outLength = outArray.length
    const b = oriLength - outLength
    const array = []
    let j = 0
    for (let i = 0; i < oriLength; i += 1) {
      if (oriArray[i] === outArray[j]) {
        j += 1
        // eslint-disable-next-line no-continue
        continue
      } else {
        array.push(i)
      }
    }
    if (
      array.length > 0 &&
      j === outLength &&
      array.length + outLength === oriLength
    ) {
      if (!this.isNumberContinuous(array)) {
        return false
      } //  保证只发生一处
      return [array[0], b]
    }
    return false
  }

  /**
   * 执行 单词去除 tony is good man -> good man
   * @param ori 源列数据
   * @param array [a, b] // 从第a个单词开始，去除b个单词
   */
  private removeStr(ori: string, array: Array<any>) {
    const oriArray = ori.split(' ')
    oriArray.splice(array[0], array[array.length - 1])
    return oriArray.join(' ')
  }

  /**
   * 检测 数组里的数字是否连续
   * @param array<number>
   * @returns true/false
   */
  private isNumberContinuous(array: Array<number>) {
    let isContinuation = true
    let i = array[0]
    // eslint-disable-next-line unicorn/no-for-loop
    for (let j = 0; j < array.length; j += 1) {
      if (array[j] !== i) {
        isContinuation = false
        break
      }
      i += 1
    }
    return isContinuation
  }

  /**
   * 检测是否符合 保留a位小数，a为正整数 3.456 -> 3.5 ROUND/FLOOR  || 特殊情况 3.45 -》 3
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns [type, a]  何种类型的保留，保留a为小数
   */
  private ifRetainDecimals(ori: string, destination: string) {
    const pos = destination.split('.')[1]?.length ?? 0 // 考虑小数 -> 整数的情况

    const padding = 10 ** pos
    if (
      Math.round(Number.parseFloat(ori) * padding) / padding ===
      Number.parseFloat(destination)
    ) {
      return ['round', pos]
    }
    if (
      Math.floor(Number.parseFloat(ori) * padding) / padding ===
      Number.parseFloat(destination)
    ) {
      return ['floor', pos]
    }
    if (
      Math.ceil(Number.parseFloat(ori) * padding) / padding ===
      Number.parseFloat(destination)
    ) {
      return ['ceil', pos]
    }
    return false
  }

  /**
   * 执行 单词去除 保留a位小数，a为正整数
   * @param ori 源列数据
   * @param [type, a]  何种类型的保留，保留a为小数
   */
  private retainDecimals(ori: string, array: any) {
    if (this.columnData.desc !== 'decimal') {
      return ''
    }
    const type = array[0]
    const a = array[1]
    const padding = 10 ** a
    const pos = ori.split('.')[1]?.length ?? 0
    if (this.defineDataType(ori) === 'int' || pos < a) {
      return Number.parseFloat(ori).toFixed(a)
    } //  当小数的数据中含有整数的时候； 原数据小数位数 小于 保留的小数位数
    if (type === 'round') {
      return this.formatDecimal(
        String(Math.round(Number.parseFloat(ori) * padding) / padding),
        a
      )
    }
    if (type === 'floor') {
      return this.formatDecimal(
        String(Math.floor(Number.parseFloat(ori) * padding) / padding),
        a
      )
    }
    return this.formatDecimal(
      String(Math.ceil(Number.parseFloat(ori) * padding) / padding),
      a
    )
  }

  /**
   * 补足小数后面的 0
   * @param output 目标数据
   * @param n 保留的位数
   */
  private formatDecimal(output: string, n: number) {
    const rs = output.indexOf('.')
    if (rs < 0) {
      output += '.'
    }
    for (let i = output.length - output.indexOf('.'); i <= n; i += 1) {
      output += '0'
    }
    return output
  }

  /**
   * 检测是否符合 小数点移位：10a*X  0.9 -> 0.009
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns a 正数向右，负数向左
   */
  private isdecimalShift(ori: number, destination: number) {
    const origin = new Big(ori)
    const result = new Big(destination)
    const a = Math.log10(+result.div(origin))
    if (Number.isInteger(a)) {
      return a
    }
    return false
  }

  /**
   * 执行 小数点移位：10a*X   0.9 -> 0.009
   * @param ori 源列数据
   * @param a 正数向右，负数向左
   */
  private decimalShift(ori: string, a: number) {
    const origin = Number.parseFloat(ori)
    const originBig = new Big(origin) //  考虑精度问题，使用big
    return String(+Big(10 ** a).times(originBig))
  }

  /**
   * 检测是否符合 整数/小数/字符串 重复  20 -> 2020
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns times 重复的次数
   */
  public isRepeated(origin: string, destination: string) {
    //  整数，小数，字符串 重复 复用代码 [传给后端的数据需要判别是integer or other repeat]
    // const ori = origin.toString(); const output = destination.toString()
    const oriLength = origin.length
    const outLength = destination.length
    if (outLength % oriLength === 0) {
      const times = outLength / oriLength
      if (origin.repeat(times) === destination) {
        return times
      }
    }
    return false
  }

  /**
   * 执行 整数/小数/字符串 重复 20 -> 2020
   * @param ori 源列数据
   * @param a times 重复的次数
   */
  public applyRepeated(origin: string, times: number) {
    return origin.repeat(times)
  }

  /**
   * 检测是否符合 整数/字符串 填充  X -> pXq
   * @param ori 源列数据
   * @param destination 目标列数据
   * @returns [p, q]  p表示首填充，q表示尾填充
   */
  public isStrFilling(origin: string, destination: string) {
    // 首尾填充字符串
    const attachString = []
    if (destination.includes(origin)) {
      const i = destination.indexOf(origin)
      attachString.push(destination.slice(0, i))
      attachString.push(destination.slice(i + origin.length))
      return attachString
    }
    return false
  }

  public checkIfRulesIncludesNoneMatched() {
    // eslint-disable-next-line no-restricted-syntax
    for (const [key, ruleValue] of this.rules) {
      console.log(key)
      if (ruleValue === 'noneRuleMatched') {
        return true
      }
    }
    return false
  }

  /**
   * 执行 整数/字符串 填充  X -> pXq
   * @param ori 源列数据
   * @param [p, q]  p表示首填充，q表示尾填充
   */
  public applyStrFilling(origin: string, stringArray: Array<string>) {
    return stringArray[0] + origin + stringArray[1]
  }

  // @Emit('confirm')
  public handleOk() {
    if (this.isEditingColumnName) {
      this.$message.error('列名已存在，请重新输入')
      return
    }
    if (this.rules.size === 0) {
      this.$message.warning('请先填入数据再确认')
      return
    }
    // eslint-disable-next-line unicorn/prevent-abbreviations
    const params: any = []
    if (this.rules.size > 1 || this.checkIfRulesIncludesNoneMatched()) {
      // eslint-disable-next-line no-restricted-syntax
      for (const [key, value] of this.changeMapping) {
        params.push({
          source: key,
          target: value,
        })
      }
    }

    const filterParameter =
      this.rules.size <= 1 && !this.checkIfRulesIncludesNoneMatched()
        ? {
            action: 'RESULT_EXTRACT',
            actionType: 'createColumn',
            col: this.columnName,
            newCol: this.newColumnName,
            description: `新增列为${this.newColumnName}`,
            ...this.specificParams,
          }
        : {
            action: 'RESULT_EXTRACT',
            actionType: 'createColumn',
            col: this.columnName,
            newCol: this.newColumnName,
            description: `新增列为${this.newColumnName}`,
            transformType: 'DEFAULT_EXTRACT',
            params,
          }

    // set New column name and type in DataStore for Table highLight
    const temporary = [
      {
        name: this.newColumnName,
        type: this.dataType.get(this.outputType) || -1,
      },
    ]
    DataStore.setNewColumnData(temporary)
    this.$emit('confirm', filterParameter)
  }

  /**
   * 关闭弹框
   */
  @Emit('config-cancel')
  public handleCancel() {
    this.isModalVisible = false
    this.clearDataAfterCancel()
  }

  private clearDataAfterCancel() {
    this.tableData.forEach((v, i) => {
      //  改变数据DOM不更新的解决方案
      Vue.set(this.tableData[i], this.newColumnName, '')
    })
    //  清空 changingMap, rules;
    this.changeMapping.clear()
    this.rules.clear()
  }

  private scrollDataMapping() {
    const { length } = this.operationUndoList
    if (length) {
      this.clearDataAfterCancel()
      for (let i = 0; i < length; i += 1) {
        const t = this.operationUndoList[i]
        // 考虑没有匹配任何规则的情况
        if (t.result) {
          this.mappingDataByRules(
            t.result,
            t.func,
            t.flag,
            t.origin,
            t.value,
            true
          )
        } else {
          this.mappingDataForNoneRulesMatched(t.origin, t.value)
        }
        this.handleMappingChange(t.origin, t.value)
      }
    }
  }

  private painationParams = {
    curPage: DataStore.tableCurPage,
    name: '_record_id_', // 如果没有字段，那就固定传 _record_id_
    pageSize: 50,
    filter: [],
  }

  private handleScroll = throttle((data: any) => this._handleScroll(data), 300)

  _headerClick(column: any) {
    if (column.title === this.newColumnName) {
      this.isEditingColumnName = true
    }
  }

  /**
   * 表格内容滚动
   */
  async _handleScroll(data: any) {
    const tableHeight = document.querySelector('.table-box')?.clientHeight
    //  因为没有 是否滚动到底部 的参数传回，所以运用scrollTop 滚动距离控制； 2400 = 32[列高] * 50
    if (
      data.scrollTop + tableHeight > 1600 * this.times &&
      this.painationParams.curPage < this.totalPages &&
      !this.isLoading
    ) {
      this.isLoading = true
      this.painationParams = {
        ...this.painationParams,
        curPage: this.painationParams.curPage + 1,
      }
      await this.getTableDataByNode()
      this.times += 1
      this.$nextTick(() => {
        this.scrollDataMapping()
      })
    }
  }

  /**
   * 获取当前节点的具体信息：列字段、表明细等
   * refresh: 刷新表格数据
   * combine: 翻页追加
   */
  async getTableDataByNode(flag: 'refresh' | 'combine' = 'combine') {
    const response = await apiGetTableData({
      data: {
        ...this.painationParams,
        table:
          flag === 'combine' && this.currentHistory
            ? this.currentHistory.data.table
            : (this.selectNode.data.output[0] || {}).tableName, // 查询数据的表名取决于当前历史记录的表名
        taskId: this.selectNode.id,
      },
    })
    this.isLoading = false
    const result = response.data.result || {}
    this.totalPages = result.page ? result.page.totalPages : 0

    DataStore.setTableDataCount(result.page ? result.page.totalElements : 0)
    DataStore.setTableData({
      head: DataStore.tableColumns,
      data:
        flag === 'combine'
          ? this.tableData.concat(result.data || [])
          : result.data || [], // 添加到表格数据的末尾或者刷新数据
      mode: 'detail',
    })
    DataStore.setTableCurPage(this.painationParams.curPage)
  }
}
</script>

<style lang="less" scoped>
.left-btn,
.right-btn {
  align-items: center;
  display: flex;

  .btn {
    align-items: center;
    border-radius: 2px;
    cursor: pointer;
    display: flex;
    font-size: 16px;
    padding: 4px;
    position: relative;

    &:hover {
      background-color: #f1f1f1;
    }
  }

  .divider {
    border-right: 1px solid #5d637e;
    height: 16px;
    margin: 0 5px;
    width: 1px;
  }

  .function-btn-spacing {
    margin: 0 10px;
  }
}

.left-btn {
  .btn {
    margin-right: 2px;
  }

  .function-run-text {
    color: #5d637e;
    font-size: 14px;
    margin-right: 10px;
  }
}

.table-info {
  float: left;
  line-height: 32px;
}

.table-box {
  // height: 800px;
  overflow-y: scroll;
}

/deep/ .ant-modal-body {
  padding: 0;
}

/deep/ .col--actived {
  border: 2px solid #cbceff;
}

.new-column-input {
  border: 0;

  &:focus {
    border: 0;
    outline: none;
  }
}

.auto-filled {
  color: #222432;
  opacity: 0.5;
}

/deep/ .elx-header--row .col--group {
  background-color: rgba(103, 113, 252, 0.1);
  color: #373b52;
  font-size: 14px;
  text-align: center;
}

/deep/ .elx-header--row .col--group.col--last {
  background-color: rgba(255, 249, 226);
}

/deep/ .elx-cell {
  color: #373b52;
}

/deep/ .new-column-input {
  background-color: rgba(0, 0, 0, 0);
}

/deep/ .elx-table.border--full .elx-table--header-wrapper {
  background: none;
}

/deep/ .elx-header--column .elx-cell--edit-icon {
  display: none;
}

.column-name {
  border: 0;
  color: #5d637e;
  font-size: 12px;
  letter-spacing: 1.12px;
  line-height: 16px;
  margin-left: 8px;
}

/deep/ .elx-header--column .elx-cell--title {
  line-height: 1;
}

/deep/ .elx-table .elx-cell {
  height: 16px;
  line-height: 16px;
}

/deep/ .elx-table .elx-header--column:not(.col--ellipsis) {
  padding: 8px 0;
}

/deep/ .elx-table .elx-body--column.col--ellipsis > .elx-cell {
  color: #373b52;
  font-size: 12px;
}

/deep/ .elx-table.elx-editable .elx-body--column {
  height: 32px;
  padding: 6px 0;
}
</style>
